package gugga.tasks
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	
	import gugga.eventHelpers.EventDescriptor;
	import gugga.eventHelpers.EventRethrower;
	import gugga.eventHelpers.Listener;
	import gugga.tasks.events.ProgressiveTaskEvent;
	import gugga.tasks.events.TaskEvent;

	[Event(name="start", type="TaskEvent")]
	[Event(name="interrupted", type="TaskEvent")]
	[Event(name="completed", type="TaskEvent")]
	[Event(name="progress", type="ProgressiveTaskEvent")]

	/**
	 * <code>ProgressiveTaskDecorator</code> is used whenever we want to dispatch 
	 * <b><i>progress</i></b>-events for tasks, that don't implement 
	 * <code>IProgressiveTask</code>. <code>ProgressiveTaskDecorator</code> wraps an 
	 * <code>ITask</code> and dispatches a fake progress for it.
	 */
	public class ProgressiveTaskDecorator extends EventDispatcher implements IProgressiveTask
	{
		private static const DEFAULT_FAKE_PROGRESS_DISPATCH_INTERVAL : Number = 300;
		
		private var mProgress : Number = 0;
		
		private var mTimer : Timer;
		
		public function get FakeProgressDispatchInterval() : Number { return mTimer.delay; }
		public function set FakeProgressDispatchInterval(aValue:Number) : void { mTimer.delay = aValue; }
	
		private var mFakeProgressDispatchPercents : Number = 10;
		public function get FakeProgressDispatchPercents() : Number { return mFakeProgressDispatchPercents; }
		public function set FakeProgressDispatchPercents(aValue:Number) : void { mFakeProgressDispatchPercents = aValue; }
		
		private var mWrappedTask : ITask;
		public function get WrappedTask() : ITask { return mWrappedTask; }
		
		public function ProgressiveTaskDecorator(aTask:ITask)
		{
			mWrappedTask = aTask;
			
			mWrappedTask.addEventListener(TaskEvent.COMPLETED, onWrappedTaskCompleted);
			EventRethrower.create(this, mWrappedTask, TaskEvent.START);
			
			mTimer = new Timer(DEFAULT_FAKE_PROGRESS_DISPATCH_INTERVAL)
		}
	
		public function start() : void 
		{
			startProgressing();
			mWrappedTask.start();
		}
		
		public function startProgressing() : void
		{
			mProgress = 0;

			mTimer.addEventListener(TimerEvent.TIMER, dispatchProgress);
			
			mTimer.start();
		} 
	
		private function onWrappedTaskCompleted(aEvent : TaskEvent) : void 
		{
			mTimer.stop();
			
			dispatchEvent(aEvent);
		}
	
		private function dispatchProgress(aEvent : Event) : void 
		{
			mProgress += mFakeProgressDispatchPercents;
			
			if(mProgress < 100)
			{
				dispatchEvent(new ProgressiveTaskEvent(ProgressiveTaskEvent.PROGRESS, mProgress, 100, mProgress));
			}
			else
			{
				mTimer.stop();
			}
		}
	
		public function isImmediatelyInterruptable() : Boolean 
		{
			return mWrappedTask.isImmediatelyInterruptable();
		}
	
		public function interrupt() : void
		{
			Listener.createSingleTimeListener(
					new EventDescriptor(mWrappedTask, TaskEvent.INTERRUPTED),
					onWrappedTaskInterrupted);
			
			mWrappedTask.interrupt();
		}
		
		private function onWrappedTaskInterrupted(aEvent : TaskEvent) : void 
		{
			dispatchEvent(new TaskEvent(TaskEvent.INTERRUPTED));
		}
		
		public function getProgress() : Number 
		{
			return mProgress;
		}
	
		public function isRunning() : Boolean 
		{
			return mWrappedTask.isRunning();
		}
	}
}